package IC.SymbolTable;

import java.util.LinkedHashMap;
import java.util.Map;


public class BlockSymbolTable extends SymbolTable 
{

	protected Map<String,VariableSymbol> varEntries = new LinkedHashMap<String,VariableSymbol>();

	public BlockSymbolTable(SymbolTable parent) 
	{
		super(null, parent);	
		this.stt = symbolTableType.BLOCK;
	}
	
	
	public boolean isDeclaired(String id)
	{
		
		boolean b = false;
		if (varEntries.containsKey(id))
		{
			return true;
		}
		
		if (parentSymbolTable != null)
		{
			b= ((BlockSymbolTable)parentSymbolTable).isDeclaired(id);
		}
		
		return b;
	}

	// checks if the symbol was already declared in the current scope
	public boolean isDeclaredAlreadyInCurrScopeBlock(String symId)
	{
		if(varEntries.containsKey(symId))
		{
			return true;
		}

		return false;
	}

	public VariableSymbol lookupSymbolInCurrScopeBlock (String id)
	{
		if (varEntries == null)
		{
			return null;			
		}

		return  varEntries.get(id);
	}

	public VariableSymbol lookupSymbolBlock (String id,int line)
	{
		VariableSymbol vs = varEntries.get(id);
		if  ( ((vs == null)||(vs.getLine()>line)) && (parentSymbolTable != null))
		{
			if (parentSymbolTable.getStt() == symbolTableType.BLOCK)
			{
				vs = ((BlockSymbolTable) parentSymbolTable).lookupSymbolBlock(id,line);
			}
			
			if (parentSymbolTable.getStt() == symbolTableType.METHOD)
			{
				vs=((MethodSymbolTable) parentSymbolTable).lookupSymbol(id);
			}
			
			if (parentSymbolTable.getStt() == symbolTableType.CLASS)
			{
				vs=(VariableSymbol) ((ClassSymbolTable) parentSymbolTable).lookupFieldSymbol(id);
			}
		}
		return vs;

	}


	public void addVariableSymbol(String name, String typeName,int line) throws SemanticError
	{
		if (!isDeclaredAlreadyInCurrScopeBlock(name))
		{
			this.varEntries.put(name, new VariableSymbol(name,typeName,line));
		}

		else
		{
			throw new SemanticError("VariableSymbol "  + name + " was already declared");
		}
	}

	
	

	public String toString(String path)
	{
		String str = "Statement Block Symbol Table ( located in " + path + " )";

		// print list of symbols (local variables)
		for(VariableSymbol vs: varEntries.values())
		{
			str += "\n\tLocal variable: "+vs.getType().getName()+" "+vs.getId();
		}

		// update path to include another "statement block in "
		path = "statement block in "+path;

		// print list of children tables (these tables can be only of type BlockSymbolTabley)
		if(!childrenSymbolTables.isEmpty())
		{
			str += "\nChildren tables: ";
			for(SymbolTable st : childrenSymbolTables)
			{
				str += "statement block in "+path+", ";
			}

			str = str.substring(0, str.length()-2);
		}
		str += "\n\n";


		// recursively print block symbol tables
		for(SymbolTable st : childrenSymbolTables)
		{
			str += ((BlockSymbolTable)st).toString(path);
		}

		return str;
	}




	public ClassSymbolTable getEnclosingClassSymbolTable()
	{
		if (this.parentSymbolTable.stt == symbolTableType.CLASS)
		{
			return (ClassSymbolTable) parentSymbolTable;
		}

		return ((BlockSymbolTable)parentSymbolTable).getEnclosingClassSymbolTable();
	}








}
